/*
 *	ApOS (Another Project software for s3c2410)
 *	
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License version 2 as
 *	published by the Free Software Foundation.
 *			
 *
 */
#include "../include/s3c2410/s3c2410.h"
#include "../include/s3c2410/nand_flash.h"
static unsigned char seBuf[16]={0xff};

unsigned short nf_checkId(void)
{
	int i;
	unsigned short id;
	NF_nFCE_L();		//chip enable
	
	NF_CMD(0x90);		//Read ID
	NF_ADDR(0x0);
	for(i=0;i<10;i++);	//wait tWB(100ns)
	
	id=NF_RDDATA()<<8;	// Maker code(K9S1208V:0xec)
	id|=NF_RDDATA();	// Devide code(K9S1208V:0x76)
	
	NF_nFCE_H();		//chip enable
	return id;
}

static void nf_reset(void)
{
	int i;
	NF_nFCE_L();		//chip enable
	NF_CMD(0xFF);		//reset command
	for(i=0;i<10;i++);  	//tWB = 100ns.
	NF_WAITRB(); 		//wait 200~500us;
	NF_nFCE_H();		//chip disable
}

void nf_init(void)
{
	rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);	
	//	     1  	1    	1     	1   	1      xxx     r xxx,      r xxx        
	//	     En 	r	r       ECCR    nFCE=H tACLS   tWRPH0      tWRPH1
	nf_reset();
}


void nf_read(unsigned int src_addr,unsigned  char *desc_addr,int size)
{
	int i;
	unsigned int column_addr=src_addr%512;			// column address
	unsigned int page_address=(src_addr>>9);		// page addrress
	unsigned char *buf=desc_addr;
	while((unsigned int)buf<(unsigned int)(desc_addr)+size)
	{
		NF_nFCE_L();					// enable chip
		if(column_addr>255)				// 2end halft
		{
			NF_CMD(0x01);				// Read2 command.   cmd 0x01: Read command(start from 2end half page)
		} 
		else
		{
			NF_CMD(0x00);				// 1st halft?
		}
		NF_ADDR(column_addr&0xff);	    		// Column Address
		NF_ADDR(page_address&0xff);			// Page Address
		NF_ADDR((page_address>>8)&0xff);		// ...
		NF_ADDR((page_address>>16)&0xff);		// ..
		for(i=0;i<10;i++);				// wait tWB(100ns)/////??????
		NF_WAITRB();					// Wait tR(max 12us)
	
		// Read from main area
		for(i=column_addr;i<512;i++)
		{
			*buf++=NF_RDDATA();
		}
		NF_nFCE_H();					// disable chip
		column_addr=0;
		page_address++;
	}
	return ;
}

int nf_erase_block(unsigned int desc_addr)
{
	unsigned int block_address=desc_addr>>9;
	int i;
	NF_nFCE_L();
	NF_CMD(0x60);			// Erase one block 1st command
	NF_ADDR(block_address&0xff);	// Page number=0
	NF_ADDR((block_address>>8)&0xff);
	NF_ADDR((block_address>>16)&0xff);
	NF_CMD(0xd0);			// Erase one blcok 2nd command
	for(i=0;i<10;i++);		// wait tWB(100ns)//??????
	NF_WAITRB();			// Wait tBERS max 3ms.
	NF_CMD(0x70);			// Read status command
	if (NF_RDDATA()&0x1)		// Erase error
	{	
		NF_nFCE_H();
		return 1;
	}
	else 
	{
		NF_nFCE_H();
		return 0;
	}
}

int nf_write(unsigned char *src_addr,unsigned  int desc_addr,const int size)
{
	int i;
	unsigned int column_addr=desc_addr%512;			// column address
	unsigned int page=(desc_addr>>9);			// page addrress
	unsigned char *buf=src_addr;
	
	for(i=0;i<((size+(512*32-1))/(512*32));i++)
		nf_erase_block(desc_addr+(i*512*32));
	
	while((unsigned int)buf<(unsigned int)(src_addr)+size)
	{
		NF_RSTECC();					// Initialize ECC. S3C2410 supports only 512-Byte ECC checking, so it is
								// required to set ECC initialized per 512 Bytes(1 Page).
		NF_nFCE_L();					// enable chip
		if(column_addr>255)//2end halft
		{
			NF_CMD(0x01);				// Read2 command.   cmd 0x01: Read command(start from 2end half page)
			NF_CMD(0x80);
		} 
		else//1st halft
		{
			NF_CMD(0x00);
			NF_CMD(0x80);
		}
		NF_ADDR(column_addr&0xff);	    			// Column Address
		NF_ADDR(page&0xff);				// Page Address
		NF_ADDR((page>>8)&0xff);			// ...
		NF_ADDR((page>>16)&0xff); 			// ..
		for(i=0;i<10;i++);				// wait tWB(100ns)/////??????
		NF_WAITRB();					// Wait tR(max 12us)
	
		// write from main area
		for(i=column_addr;i<512;i++)
		{
			NF_WRDATA(*buf++);
		}
		
		seBuf[0]=rNFECC0;
		seBuf[1]=rNFECC1;
		seBuf[2]=rNFECC2;

		// Write to spare array
		for(i=0;i<16;i++)
		{
			NF_WRDATA(seBuf[i]);
 		}
		
		NF_CMD(0x10);			// confirm command(write 2ed cycle ),programming process
						// start by the confirm command
    		for(i=0;i<10;i++);		// tWB = 100ns.
		NF_WAITRB();			// wait tPROG 200~500us;
	
 		NF_CMD(0x70);			// Read status command(read status data from i/o pin)
		for(i=0;i<3;i++);  		// twhr=60ns
		if(NF_RDDATA()&0x1)		// Page write error
		{	
  	  		NF_nFCE_H();
			return 1;		// write page failed
 		}
		else
		{
			NF_nFCE_H();
		}
		column_addr=0;
		page++;
	}
	return 0;				// write page complete
}
